using System;
using CommonDomain.Persistence;

namespace Sponsorship.Domain.Persons
{
    /// <summary>
    /// Handles domain commands dealing with <see cref="Person"/> instances.
    /// </summary>
    public class PersonCommandHandler :
        ICommandHandler<EnterPerson>,
        ICommandHandler<ChangePerson>,
        ICommandHandler<DeletePerson>,
        ICommandHandler<EnterPersonAssociation>,
        ICommandHandler<ChangePersonAssociation>,
        ICommandHandler<DeletePersonAssociation>,
        ICommandHandler<SuggestPresent>,
        ICommandHandler<ChangeSuggestedPresent>,
        ICommandHandler<DeleteSuggestedPresent>
    {
        private readonly IRepository _repository;

        public PersonCommandHandler(IRepository repository)
        {
            _repository = repository;
        }

        public void Handle(EnterPerson command)
        {
            Person person = new Person(command.PersonId, command.FirstName, command.LastName, command.DateOfBirth, command.TelephoneNumber, command.Status, command.Comment);
            SavePerson(person);
        }

        public void Handle(ChangePerson command)
        {
            Person person = _repository.GetById<Person>(command.PersonId, command.Version);
            person.Change(command.FirstName, command.LastName, command.DateOfBirth, command.TelephoneNumber, command.Status, command.Comment);
            SavePerson(person);
        }

        public void Handle(DeletePerson command)
        {
            Person person = _repository.GetById<Person>(command.PersonId, command.Version);
            person.Delete();
            SavePerson(person);
        }

        public void Handle(EnterPersonAssociation command)
        {
            Person person = _repository.GetById<Person>(command.PersonId, command.Version);
            person.AssociatePerson(command.PersonAssociationId, command.AssociatedPersonId, command.PersonAssociationTemplateId, command.AssociationName, command.Comment);
            SavePerson(person);
        }

        public void Handle(ChangePersonAssociation command)
        {
            Person person = _repository.GetById<Person>(command.PersonId, command.Version);
            person.ChangePersonAssociation(command.PersonAssociationId, command.AssociatedPersonId, command.PersonAssociationTemplateId, command.AssociationName, command.Comment);
            SavePerson(person);
        }

        public void Handle(DeletePersonAssociation command)
        {
            Person person = _repository.GetById<Person>(command.PersonId, command.Version);
            person.DeletePersonAssociation(command.PersonAssociationId);
            SavePerson(person);
        }

        public void Handle(SuggestPresent command)
        {
            Person person = _repository.GetById<Person>(command.PersonId, command.Version);
            person.SuggestPresent (command.SuggestedPresentId, command.PresentTemplateId, command.PresentData, command.Comment);
            SavePerson(person);
        }

        public void Handle(ChangeSuggestedPresent command)
        {
            Person person = _repository.GetById<Person>(command.PersonId, command.Version);
            person.ChangeSuggestedPresent (command.SuggestedPresentId, command.PresentTemplateId, command.PresentData, command.Comment);
            SavePerson(person);
        }

        public void Handle(DeleteSuggestedPresent command)
        {
            Person person = _repository.GetById<Person>(command.PersonId, command.Version);
            person.DeleteSuggestedPresent (command.SuggestedPresentId);
            SavePerson(person);
        }        

        private void SavePerson(Person person)
        {
            _repository.Save(person, Guid.NewGuid()); // Every commit has a new ID
        }
    }
}